package migrate

import (
	"fmt"
	"gitee.com/hexug/go-tools/logger"
	"gitee.com/hexug/kube-sync/apps/cleandata"
	"gitee.com/hexug/kube-sync/apps/resource"
	"go.uber.org/zap"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	rbacv1 "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
	"os"
	"strings"
)

func (s *WorkloadMigrator) listDeployments(req *resource.ListDeployRequest) map[string][]*appsv1.Deployment {
	dps, err := s.dpsvc.ListDeploy(s.ctx, req)
	if err != nil {
		logger.L().Fatal(err)
	}
	ishas := false
	for ns, item := range dps {
		for _, dp := range item {
			ishas = true
			logger.L().Infow("找到Deployment", "namespace", ns, "resource", dp.Name)
		}
	}
	if !ishas {
		logger.L().Info("没有需要处理的资源")
		os.Exit(0)
	}
	return dps
}

func (s *WorkloadMigrator) cleanWorkloads(dps *resource.ListWorkloadRespone) *cleandata.CleanWorkloadResponse {
	if dps == nil || len(dps.Items) == 0 {
		return nil
	}

	// 如果没有目标命名空间，直接清洗原数据
	if len(s.destNamespaces) == 0 {
		res, err := s.clndsvc.CleanWorkload(s.ctx, dps)
		if err != nil {
			logger.L().Fatal(err)
		}
		return res
	}

	newResp := &resource.ListWorkloadRespone{
		Items: make(map[string]*resource.WorkloadCore, len(dps.Items)*len(s.destNamespaces)),
	}
	// 处理替换掉namespace
	for _, newNamespace := range s.destNamespaces {
		for key, core := range dps.Items {
			if core == nil || core.Workload == nil {
				continue
			}

			// 深拷贝 Workload，防止被上一次修改污染
			obj, ok := core.Workload.(runtime.Object)
			if !ok {
				logger.L().Warn("unknown workload type", zap.String("key", key))
				continue
			}

			cloned := obj.DeepCopyObject()
			// 修改 namespace
			reflectSetNamespace(cloned, newNamespace)
			updateTemplateNamespace(cloned, newNamespace)

			newCore := &resource.WorkloadCore{
				ExcludeWorkloadCore: &resource.ExcludeWorkloadCore{
					Namespace:    newNamespace,
					Workload:     core.ExcludeWorkloadCore.Workload,
					WorkloadType: core.ExcludeWorkloadCore.WorkloadType,
				},
				Workload: cloned,
			}

			// 构造新 key
			parts := strings.SplitN(key, ":", 3)
			if len(parts) == 3 {
				newKey := fmt.Sprintf("%s:%s:%s", newNamespace, parts[1], parts[2])
				newResp.Items[newKey] = newCore
			} else {
				newResp.Items[key] = newCore
			}
		}
	}
	res, err := s.clndsvc.CleanWorkload(s.ctx, newResp)
	if err != nil {
		logger.L().Fatal(err)
	}
	return res
}

func (s *WorkloadMigrator) cleanServices(wks []interface{}, clientSet *kubernetes.Clientset) *cleandata.CleanServiceResponse {
	reqGetWks := resource.NewFromWorkloadGetResourceRequest()
	reqGetWks.ClientSet = clientSet
	reqGetWks.AddWorkload(wks...)
	svcs, err := s.dpsvc.FromWorkloadGetService(s.ctx, reqGetWks)
	if err != nil {
		logger.L().Fatal(err)
	}

	req := cleandata.NewCleanServiceRequest()
	req.AddService(svcs...)
	if len(s.destNamespaces) == 0 {
		res, err := s.clndsvc.CleanService(s.ctx, req)
		if err != nil {
			logger.L().Fatal(err)
		}
		return res
	}
	newReq := &cleandata.CleanServiceRequest{
		Services: make([]*resource.ListServiceRespone, len(svcs)*len(s.destNamespaces)),
	}
	// 处理替换掉namespace
	for _, newNamespace := range s.destNamespaces {
		for _, core := range req.Services {
			if core == nil || core.Services == nil {
				continue
			}

			// 深拷贝 Workload，防止被上一次修改污染

			cloned := core.Services.DeepCopyObject()
			// 修改 namespace
			reflectSetNamespace(cloned, newNamespace)
			updateNonWorkloadNamespace(cloned, newNamespace)

			newCore := resource.NewListServiceRespone()
			newCore.Services = cloned.(*corev1.Service)
			newCore.Namespace = newNamespace
			newCore.Workload = core.Workload
			newCore.WorkloadType = core.WorkloadType
			newReq.AddService(newCore)
		}
	}
	res, err := s.clndsvc.CleanService(s.ctx, newReq)
	if err != nil {
		logger.L().Fatal(err)
	}
	return res
}

func (s *WorkloadMigrator) cleanConfigMap(wks []interface{}, clientSet *kubernetes.Clientset) *cleandata.CleanConfigMapResponse {
	reqGetWks := resource.NewFromWorkloadGetResourceRequest()
	reqGetWks.ClientSet = clientSet
	reqGetWks.AddWorkload(wks...)
	cms, err := s.dpsvc.FromWorkloadGetConfigMaps(s.ctx, reqGetWks)
	if err != nil {
		logger.L().Fatal(err)
	}
	req := cleandata.NewCleanConfigMapRequest()
	req.AddConfigMap(cms...)

	if len(s.destNamespaces) == 0 {
		res, err := s.clndsvc.CleanConfigMap(s.ctx, req)
		if err != nil {
			logger.L().Fatal(err)
		}
		return res
	}
	newReq := &cleandata.CleanConfigMapRequest{
		ConfigMaps: []*resource.ListConfigMapResponse{},
	}
	// 处理替换掉namespace
	for _, newNamespace := range s.destNamespaces {
		for _, core := range req.ConfigMaps {
			if core == nil || core.ConfigMaps == nil {
				continue
			}
			newCore := resource.NewListConfigMapResponse(resource.NewConfigMapCore(newNamespace, core.WorkloadType, core.Workload, core.Names...))

			for _, cm := range core.ConfigMaps {
				// 深拷贝 Workload，防止被上一次修改污染

				cloned := cm.DeepCopyObject()
				// 修改 namespace
				reflectSetNamespace(cloned, newNamespace)
				updateNonWorkloadNamespace(cloned, newNamespace)
				newCore.SetConfigMap(cloned.(*corev1.ConfigMap))
			}
			newReq.AddConfigMap(newCore)
		}
	}
	res, err := s.clndsvc.CleanConfigMap(s.ctx, newReq)
	if err != nil {
		logger.L().Fatal(err)
	}
	return res
}

func (s *WorkloadMigrator) CleanRBAC(wks []interface{}, clientSet *kubernetes.Clientset) *cleandata.CleanRBACResponse {
	req := resource.NewFromWorkloadGetResourceRequest()
	req.ClientSet = clientSet
	req.AddWorkload(wks...)
	resRBAC, err := s.dpsvc.FromWorkloadGetRBAC(s.ctx, req)
	if err != nil {
		logger.L().Fatal(err)
	}

	if len(s.destNamespaces) == 0 {
		res, err := s.clndsvc.CleanRBAC(s.ctx, resRBAC)
		if err != nil {
			logger.L().Fatal(err)
		}
		return res
	}
	newRBAC := resource.NewFromWorkloadGetRBACResponse()
	// 处理替换掉namespace
	for _, newNamespace := range s.destNamespaces {
		for key, core := range resRBAC.Items {
			if core == nil || core.ServiceAccount == nil {
				continue
			}
			newCore := resource.NewRBACInfo()

			// 处理sa
			clonedSa := core.ServiceAccount.DeepCopyObject()
			reflectSetNamespace(clonedSa, newNamespace)
			updateNonWorkloadNamespace(clonedSa, newNamespace)
			newCore.ServiceAccount = clonedSa.(*corev1.ServiceAccount)

			// 处理rb
			for _, rb := range core.RoleBindings {
				clonedRb := rb.DeepCopyObject()
				reflectSetNamespace(clonedRb, newNamespace)
				updateNonWorkloadNamespace(clonedRb, newNamespace)
				newCore.AddRoleBinding(clonedRb.(*rbacv1.RoleBinding))
			}

			// 处理crb
			for _, crb := range core.ClusterRBs {
				clonedCrb := crb.DeepCopyObject()
				reflectSetNamespace(clonedCrb, newNamespace)
				updateNonWorkloadNamespace(clonedCrb, newNamespace)
				newCore.AddClusterRoleBinding(clonedCrb.(*rbacv1.ClusterRoleBinding))
			}

			// 处理role
			for _, role := range core.Roles {
				clonedRole := role.DeepCopyObject()
				reflectSetNamespace(clonedRole, newNamespace)
				updateNonWorkloadNamespace(clonedRole, newNamespace)
				newCore.AddRole(clonedRole.(*rbacv1.Role))
			}

			// 处理crole
			for _, crole := range core.ClusterRoles {
				clonedCrole := crole.DeepCopyObject()
				reflectSetNamespace(clonedCrole, newNamespace)
				updateNonWorkloadNamespace(clonedCrole, newNamespace)
				newCore.AddClusterRole(clonedCrole.(*rbacv1.ClusterRole))
			}
			// 构造新 key
			parts := strings.SplitN(key, ":", 3)
			if len(parts) == 3 {
				newKey := fmt.Sprintf("%s:%s:%s", newNamespace, parts[1], parts[2])
				newRBAC.Items[newKey] = newCore
			} else {
				newRBAC.Items[key] = newCore
			}
		}
	}
	res, err := s.clndsvc.CleanRBAC(s.ctx, newRBAC)
	if err != nil {
		logger.L().Fatal(err)
	}
	return res
}

func (s *WorkloadMigrator) CleanPvPvc(wks []interface{}, clientSet *kubernetes.Clientset) *cleandata.CleanPvPvcResponse {
	req := resource.NewFromWorkloadGetResourceRequest()
	req.ClientSet = clientSet
	req.AddWorkload(wks...)
	resPvPvc, err := s.dpsvc.FromWorkloadGetPVPVC(s.ctx, req)
	if err != nil {
		logger.L().Fatal(err)
	}
	if len(s.destNamespaces) == 0 {
		res, err := s.clndsvc.CleanPvPvc(s.ctx, resPvPvc)
		if err != nil {
			logger.L().Fatal(err)
		}
		return res
	}
	newPvPvc := resource.NewFromWorkloadGetPVPVCResponse()
	for _, newNamespace := range s.destNamespaces {
		for key, core := range resPvPvc.Items {
			newCore := resource.NewWorkloadVolumes()
			for _, pv := range core.PVs {
				clonedPv := pv.DeepCopyObject()
				updateNonWorkloadNamespace(clonedPv, newNamespace)
				newCore.AddPV(clonedPv.(*corev1.PersistentVolume))
			}
			for _, pvc := range core.PVCs {
				clonedPvc := pvc.DeepCopyObject()
				reflectSetNamespace(clonedPvc, newNamespace)
				updateNonWorkloadNamespace(clonedPvc, newNamespace)
				newCore.AddPVC(clonedPvc.(*corev1.PersistentVolumeClaim))
			}
			// 构造新 key
			parts := strings.SplitN(key, ":", 3)
			if len(parts) == 3 {
				newKey := fmt.Sprintf("%s:%s:%s", newNamespace, parts[1], parts[2])
				newPvPvc.AddWorkloadVolumes(newKey, newCore)
			} else {
				newPvPvc.AddWorkloadVolumes(key, newCore)
			}
		}
	}
	res, err := s.clndsvc.CleanPvPvc(s.ctx, newPvPvc)
	if err != nil {
		logger.L().Fatal(err)
	}
	return res
}

func (s *WorkloadMigrator) CleanSecret(wks []interface{}, set *kubernetes.Clientset) *cleandata.CleanSecretResponse {
	req := resource.NewFromWorkloadGetResourceRequest()
	req.ClientSet = set
	req.AddWorkload(wks...)
	resSecret, err := s.dpsvc.FromWorkloadGetSecret(s.ctx, req)
	if err != nil {
		logger.L().Fatal(err)
	}
	if len(s.destNamespaces) == 0 {
		res, err := s.clndsvc.CleanSecret(s.ctx, resSecret)
		if err != nil {
			logger.L().Fatal(err)
		}
		return res
	}
	newSecret := resource.NewFromWorkloadGetSecretResponse()
	for _, newNamespace := range s.destNamespaces {
		for key, core := range resSecret.Items {
			newCore := resource.NewSecretCore(newNamespace)
			for _, secret := range core.Secrets {
				clonedSecret := secret.DeepCopyObject()
				reflectSetNamespace(clonedSecret, newNamespace)
				updateNonWorkloadNamespace(clonedSecret, newNamespace)
				newCore.AddSecret(clonedSecret.(*corev1.Secret))
			}
			// 构造新 key
			parts := strings.SplitN(key, ":", 3)
			if len(parts) == 3 {
				newKey := fmt.Sprintf("%s:%s:%s", newNamespace, parts[1], parts[2])
				newSecret.AddSecretCore(newKey, newCore)
			} else {
				newSecret.AddSecretCore(key, newCore)
			}
		}
	}

	res, err := s.clndsvc.CleanSecret(s.ctx, newSecret)
	if err != nil {
		logger.L().Fatal(err)
	}
	return res
}
